/*
   Manipulate window lists
   Created by Randall Maas, Saturday January 31 2009
   Copyright (c) 2009, Randall Maas
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

   Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   Neither the name of Blackwood Designs, LLC nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   THE POSSIBILITY OF SUCH DAMAGE.
*/

using System ;
using System . Runtime . InteropServices;
using System . Diagnostics;

public static partial class Win32
{
   #region Win32 API
   /// <summary>
   /// Delegate for the EnumChildWindows method, called with each step of enumeration
   /// </summary>
   /// <param name="hWnd">Window handle</param>
   /// <param name="parameter">Caller-defined variable; we use it for a pointer to the real delegate</param>
   /// <returns>true to keep enumerating, false to stop</returns>
   /// [return: MarshalAs(UnmanagedType.Bool)]
   delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

   /// <summary>
   /// Goes thru each of the windows and calls the specified function
   /// </summary>
   /// <param name="lpEnumFunc">Function to call</param>
   /// <param name="lParam">Hint or other paramter to pass to function</param>
   /// <returns></returns>
   [DllImport("user32.dll")]
   [return: MarshalAs(UnmanagedType.Bool)]
   static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

   /// <summary>
   /// Goes thru each of the windows that are a child of the specified window, and calls
   /// the specified function
   /// </summary>
   /// <param name="hwndParent"></param>
   /// <param name="lpEnumFunc">Function to call</param>
   /// <param name="lParam">Hint or other paramter to pass to function</param>
   /// <returns></returns>
   [DllImport("user32.dll")]
   [return: MarshalAs(UnmanagedType.Bool)]
   static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);


   /// <summary>
   /// Goes thru each of the windows that are a child of the specified window, and
   /// calls the specified funciton
   /// </summary>
   /// <param name="hDesktop"></param>
   /// <param name="lpfn">Function to call</param>
   /// <param name="lParam">Hint or other paramter to pass to function</param>
   /// <returns></returns>
   [DllImport("user32.dll", ExactSpelling=false, CharSet=CharSet.Auto, SetLastError=true)]
   [return: MarshalAs(UnmanagedType.Bool)]
   static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpfn, IntPtr lParam);
   #endregion

   #region Helper Delegate
   /// <summary>
   /// Callback method to be used when enumerating windows.
   /// </summary>
   /// <param name="handle">Handle of the next window</param>
   /// <param name="pointer">Pointer to a GCHandle that holds a reference to the real delegate</param>
   /// <returns>True to continue the enumeration, false to bail</returns>
   private static bool EnumWindow(IntPtr Handle, IntPtr Pointer)
   {
      GCHandle DHandle = GCHandle . FromIntPtr(Pointer);
      EnumWindowsDelegate D = DHandle . Target as EnumWindowsDelegate;
      return D(Handle);
    }

   #endregion

   /// <summary>
   /// Delegate to use when enumerating a set of windows
   /// </summary>
   /// <param name="WinHandle">The current window in the list/set</param>
   /// <returns>true to keep enumerating, false to stop</returns>
   internal delegate bool EnumWindowsDelegate(IntPtr WinHandle);

   /// <summary>
   /// Enumerates the set of windows
   /// </summary>
   /// <param name="D">Enumeration delegate</param>
   /// <returns>true on success, otherwise error</returns>
   internal static bool WinEnumerate(EnumWindowsDelegate D)
   {
      GCHandle DHandle = GCHandle . Alloc(D);
      bool Ret = false;
      try
      {
         Ret = EnumWindows(EnumWindow, GCHandle . ToIntPtr(DHandle));
      }
      finally
      {
         if (DHandle . IsAllocated)
           DHandle . Free();
      }
      return Ret;
   } 

   /// <summary>
   /// Enumerates the children of the given window
   /// </summary>
   /// <param name="Parent">The parent window</param>
   /// <param name="D">Enumeration delegate</param>
   /// <returns>true on success, otherwise error</returns>
   internal static bool WinChildren(IntPtr Parent, EnumWindowsDelegate D)
   {
      GCHandle DHandle = GCHandle . Alloc(D);
      bool Ret = false;
      try
      {
         Ret = EnumChildWindows(Parent, EnumWindow, GCHandle . ToIntPtr(DHandle));
      }
      finally
      {
         if (DHandle . IsAllocated)
           DHandle . Free();
      }
      return Ret;
   } 

   /// <summary>
   /// Enumerates the windows of the given desktop
   /// </summary>
   /// <remarks>
   /// The desktop handle can crom from CreateDesktop, GetThreadDesktop, OpenDesktop, or OpenInputDesktop 
   /// </remarks>
   /// <param name="Desktop">The handle to the desktop</param>
   /// <param name="D">Enumeration delegate</param>
   /// <returns>true on success, otherwise error</returns>
   internal static bool WinDesktop(IntPtr Desktop, EnumWindowsDelegate D)
   {
      GCHandle DHandle = GCHandle . Alloc(D);
      bool Ret = false;
      try
      {
         Ret = EnumDesktopWindows(Desktop, EnumWindow, GCHandle . ToIntPtr(DHandle));
      }
      finally
      {
         if (DHandle . IsAllocated)
           DHandle . Free();
      }
      return Ret;
   } 

   /// <summary>
   /// Finds a window by its designated class (optional) and name
   /// </summary>
   /// <param name="lpClassName"></param>
   /// <param name="lpWindowName"></param>
   /// <returns></returns>
   /// <remarks>
   /// HWND hWndTaskbar = FindWindow(NULL, "Shell_TrayWnd");
   /// HWND hWndDesktopIcons = FindWindow("Progman", "Program Manager");
   /// </remarks>
   [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   static extern IntPtr FindWindow([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, [MarshalAs(UnmanagedType.LPWStr)]string lpWindowName);
}
